<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI聊天界面 - 对话分组</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Arial', sans-serif;
        }

        body {
            background-color: #f5f5f5;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        .chat-container {
            width: 90%;
            max-width: 1000px;
            height: 90vh;
            display: flex;
            background-color: white;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
        }

        .sidebar {
            width: 250px;
            background-color: #2c3e50;
            color: white;
            padding: 20px;
            overflow-y: auto;
        }

        .sidebar-header {
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        }

        .sidebar-header h2 {
            font-size: 18px;
            margin-bottom: 10px;
        }

        .new-chat-btn {
            width: 100%;
            padding: 10px;
            background-color: #3498db;
            border: none;
            border-radius: 5px;
            color: white;
            cursor: pointer;
            margin-bottom: 15px;
            transition: background-color 0.3s;
        }

        .new-chat-btn:hover {
            background-color: #2980b9;
        }

        .chat-list {
            list-style: none;
            max-height: 600px;
            overflow-y: auto;
            scrollbar-width: none;
            /* Firefox */
            -ms-overflow-style: none;
            /* IE and Edge */
        }

        .chat-list::-webkit-scrollbar-thumb {
            background-color: transparent;
            border-radius: 4px;
        }

        /* 悬停时显示滚动条 */
        .chat-list:hover::-webkit-scrollbar-thumb {
            background-color: rgba(0, 0, 0, 0.5);
        }

        .chat-list:hover {
            scrollbar-width: thin;
            /* Firefox */
        }

        .chat-item {
            padding: 5px;
            margin-bottom: 5px;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .chat-item:hover {
            background-color: rgba(255, 255, 255, 0.1);
        }

        .chat-item.active {
            background-color: #3498db;
        }

        .chat-item .delete-btn {
            float: right;
            background: none;
            border: none;
            color: white;
            cursor: pointer;
            opacity: 0.7;
        }

        .chat-item .delete-btn:hover {
            opacity: 1;
        }

        .chat-area {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: #ecf0f1;
            overflow: hidden;
        }

        .chat-header {
            padding: 15px;
            background-color: #34495e;
            color: white;
            border-bottom: 1px solid #ddd;
        }

        .chat-header textarea {
            padding: 5px;
            background-color: #304050;
            color: white;
            border-bottom: 1px solid #ddd;
            width: 100%;
            min-height: 50px;
            max-height: 500px;
            resize: vertical;
            /*vertical*/
        }

        .chat-messages {
            flex: 1;
            padding: 20px;
            overflow-y: auto;
        }

        .message {
            margin-bottom: 15px;
            max-width: 80%;
            overflow: auto;
        }

        .user-message {
            margin-left: auto;
            background-color: #3498db;
            color: white;
            padding: 10px 15px;
            border-radius: 18px 18px 0 18px;
        }

        .user-message img {
            max-width: 90%;
            max-height: 300px;
        }

        .ai-message {
            margin-right: auto;
            background-color: white;
            color: #333;
            padding: 10px 15px;
            border-radius: 18px 18px 18px 0;
        }

        .chat-input {
            padding: 15px;
            background-color: white;
            border-top: 1px solid #ddd;
            display: flex;
        }

        .chat-input textarea {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            margin-right: 10px;
            min-height: 50px;
            max-height: 500px;
            resize: vertical;
            /*vertical*/
        }

        .chat-input button {
            padding: 10px 20px;
            background-color: #3498db;
            border: none;
            border-radius: 5px;
            color: white;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .chat-input button:hover {
            background-color: #2980b9;
        }

        .chat-input img {
            display: none;
            max-width: 300px;
            max-height: 500px;
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            margin-right: 10px;
        }

        .btn {
            cursor: pointer;
        }

        .btn:hover {
            background-color: #2980b9;
            border-radius: 5px;
        }
    </style>
</head>

<body>
    <div class="chat-container">
        <div class="sidebar">
            <div class="sidebar-header">
                <h2>对话分组</h2>
                <!--button class="new-chat-btn" id="newChatBtn">新建对话</button-->

                <style>
                    .list-container {
                        list-style-type: none;
                        padding: 0;
                        margin: 0;
                        max-height: 220px;
                        overflow-y: auto;
                        /* 列表可滚动 */
                        flex: 1;
                        scrollbar-width: none;
                        /* Firefox */
                        -ms-overflow-style: none;
                        /* IE and Edge */
                    }

                    .list-container::-webkit-scrollbar-thumb {
                        background-color: transparent;
                        border-radius: 4px;
                    }

                    /* 悬停时显示滚动条 */
                    .list-container:hover::-webkit-scrollbar-thumb {
                        background-color: rgba(0, 0, 0, 0.5);
                    }

                    .list-container:hover {
                        scrollbar-width: thin;
                        /* Firefox */
                    }

                    .list-container li {
                        padding: 5px 2px;
                        border-bottom: 1px dashed #ddd;
                    }

                    .list-container li input {
                        width: 100%;
                    }

                    .list-container li select {
                        width: 100%;
                    }
                </style>
                <ul id="edit-content" class="list-container">
                    <li id="newChatBtn" class="btn">新建对话</li>
                    <li id="downloadChatBtn" class="btn" onclick="downloadJson()">下载对话</li>
                    <li class="editable-item">
                        <span id="ollama_url" class="editable-content">http://localhost:11434</span>
                    </li>
                    <li>
                        <select id="ollama_model"></select>
                    </li>
                </ul>
                <script>
                    const ollama_url = document.getElementById("ollama_url");
                    const ollama_model = document.getElementById("ollama_model");
                    async function fetchTags() {
                        try {
                            const response = await fetch(ollama_url.textContent + "/api/tags");
                            if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
                            const data = await response.json();
                            const models = {};
                            ollama_model.innerHTML = "";
                            data.models.forEach(model => {
                                const option = document.createElement("option");
                                option.value = model.name;
                                if (model.name == "qwen3:1.7b") {
                                    option.selected = true;
                                }
                                option.textContent = `模型：${model.name}，大小：${Math.floor(model.size / 1024 / 1024)} Mb`;
                                ollama_model.append(option);
                            });
                        } catch (error) {
                            console.error('Error fetching data:', error);
                        }
                    }
                    fetchTags();
                    function downloadJson() { // { "name": "aiChat", "data": data }
                        let fileName = "aiChat_chats_" + "." + Date.now().toString(16) + ".json";
                        let jsonString = JSON.stringify(CM.chats, null, 2);
                        let blob = new Blob([jsonString], { type: 'application/json' });
                        let url = URL.createObjectURL(blob);
                        let link = document.createElement('a');
                        link.href = url;
                        link.setAttribute('download', fileName);
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                        console.log("成功下载文件：" + fileName);
                    }
                </script>

            </div>
            <ul class="chat-list" id="chatList">
                <!-- 对话分组将在这里动态生成 -->
            </ul>
        </div>
        <div class="chat-area">
            <div class="chat-header" id="chatHeader">
                <textarea>新建对话</textarea>
            </div>
            <div class="chat-messages" id="chatMessages">
                <div class="message ai-message">
                    你好！我是AI助手，有什么可以帮您的吗？
                </div>
            </div>
            <div class="chat-input">
                <!--input type="text" id="messageInput" placeholder="输入消息..."-->
                <img id="previewImg" src=""></img>
                <textarea id="messageInput" placeholder="输入消息..."></textarea>
                <button id="sendBtn">发送</button>
            </div>
        </div>
    </div>

    <style>
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
        }

        .modal-content {
            background-color: white;
            padding: 20px;
            border-radius: 10px;
            width: 800px;
        }

        .modal-content textarea {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            min-height: 300px;
            max-height: 600px;
            resize: vertical;
            /*vertical*/
        }

        .modal-content button {
            padding: 10px 15px;
            background-color: #3498db;
            border: none;
            border-radius: 5px;
            color: white;
            cursor: pointer;
            margin-right: 10px;
        }

        .modal-content button.cancel {
            background-color: #95a5a6;
        }
    </style>
    <!-- 新建对话模态框 -->
    <div class="modal" id="newChatModal">
        <div class="modal-content">
            <h3>新建对话</h3>
            <!--input type="text" id="chatNameInput" placeholder="输入对话名称"-->
            <textarea id="chatNameInput" placeholder="输入对话名称"></textarea>
            <div>
                <button id="confirmNewChatBtn">确认</button>
                <button class="cancel" id="cancelNewChatBtn">取消</button>
            </div>
        </div>
    </div>

    <script>
        async function streamChat() {
            const sendBtn = document.getElementById('sendBtn');
            const chatMessagesDiv = document.getElementById('chatMessages');
            const chatIndex = CM.chats.findIndex(chat => chat.id === localStorage.getItem('currentChatId')) || 0;
            const chats = [{ "role": "system", "content": CM.chats[chatIndex].prompt }];
            CM.chats[chatIndex].messages.forEach(chat => {
                chats.push({ "role": chat.sender, "content": chat.content })
            })
            const payload = {
                model: ollama_model.value,
                messages: [...chats],
                stream: true,
                options: { temperature: 0.5, seed: 42 }
            };
            sendBtn.classList.add("btnDisabled");
            console.log(payload)
            CM.showMessage("system", "");
            const response = await fetch(ollama_url.textContent + "/api/chat", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Accept": "text/event-stream"
                },
                body: JSON.stringify(payload)
            });
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            let buffer = "";
            let messages = "";
            while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                buffer += decoder.decode(value, { stream: true });
                const chunks = buffer.split("\n");
                buffer = chunks.pop();
                for (const chunk of chunks) {
                    if (chunk.trim() === "") continue;
                    try {
                        const data = JSON.parse(chunk);
                        messages += data.message.content;
                        chatMessagesDiv.lastElementChild.textContent += data.message.content;
                        chatMessagesDiv.scrollTop = chatMessagesDiv.scrollHeight;
                    } catch (e) {
                        console.error("Failed to parse chunk:", chunk);
                    }
                }
            }
            sendBtn.classList.remove("btnDisabled");
            CM.addMessage("assistant", messages);
        }
        class ChatManager {
            constructor() {
                this.chats = JSON.parse(localStorage.getItem('aiChats')) || [];

                this.chatList = document.getElementById('chatList');
                this.chatHeader = document.getElementById('chatHeader');
                this.chatMessagesDiv = document.getElementById('chatMessages');
                this.previewImg = document.getElementById('previewImg');
                this.messageInput = document.getElementById('messageInput');

                this.newChatBtn = document.getElementById('newChatBtn');
                this.newChatModal = document.getElementById('newChatModal');
                this.chatNameInput = document.getElementById('chatNameInput');
                this.confirmNewChatBtn = document.getElementById('confirmNewChatBtn');
                this.cancelNewChatBtn = document.getElementById('cancelNewChatBtn');
                this.sendBtn = document.getElementById('sendBtn');
                this.elementListener(this);

            }
            elementListener(someVariable) {
                this.newChatBtn.addEventListener('click', () => {
                    someVariable.chatNameInput.value = '';
                    someVariable.newChatModal.style.display = 'flex';
                });
                this.confirmNewChatBtn.addEventListener('click', () => {
                    const name = someVariable.chatNameInput.value.trim();
                    if (name) {
                        someVariable.createNewChat(name);
                        someVariable.newChatModal.style.display = 'none';
                        someVariable.renderChatList();
                    }
                });
                this.cancelNewChatBtn.addEventListener('click', () => {
                    someVariable.newChatModal.style.display = 'none';
                });
                this.sendBtn.addEventListener('click', () => {
                    const content = someVariable.messageInput.value.trim();
                    //if (someVariable.previewImg.src) someVariable.showMessageImage();
                    if (content) {
                        someVariable.addMessage("user", content);
                        someVariable.showMessage("user", content);
                        someVariable.messageInput.value = '';
                        streamChat();
                        /* // 模拟AI回复
                        setTimeout(() => {
                            CM.addMessage("ai", Date.now().toString());
                        }, 1000); */
                    }
                });
                this.messageInput.addEventListener('keypress', (e) => {
                    if (e.key === 'Enter') {
                        const content = someVariable.messageInput.value.trim();
                        //if (someVariable.previewImg.src != "") someVariable.showMessageImage();
                        if (content) {
                            someVariable.addMessage("user", content);
                            someVariable.showMessage("user", content);
                            someVariable.messageInput.value = '';
                            streamChat();
                            /* // 模拟AI回复
                            setTimeout(() => {
                                someVariable.addMessage("ai", Date.now().toString());
                            }, 1000); */
                        }
                    }
                });
                this.messageInput.addEventListener('paste', function (e) {
                    if (e.clipboardData && e.clipboardData.items) {
                        const items = e.clipboardData.items;
                        for (let i = 0; i < items.length; i++) {
                            if (items[i].type.indexOf('image') !== -1) {
                                const blob = items[i].getAsFile();
                                const url = URL.createObjectURL(blob);
                                someVariable.previewImg.src = url;
                                someVariable.previewImg.style.display = 'block';
                                break;
                            }
                        }
                    }
                });
                this.messageInput.addEventListener('drop', function (e) {
                    e.preventDefault();
                    someVariable.messageInput.classList.remove('dragover');
                    const files = e.dataTransfer.files;
                    if (files.length) {
                        const file = files[0];
                        if (file.type.indexOf('image') !== -1) {
                            const url = URL.createObjectURL(file);
                            someVariable.previewImg.src = url;
                            someVariable.previewImg.style.display = 'block';
                        } else if (file.type.indexOf('json') !== -1) {
                            const reader = new FileReader();
                            reader.onload = (e) => {
                                try {
                                    someVariable.chats = JSON.parse(e.target.result);
                                    localStorage.setItem('currentChatId', someVariable.chats[0].id);
                                    someVariable.renderChatList();
                                } catch (error) {
                                    console.error("无法解析JSON文件:", error);
                                }
                            };
                            reader.onerror = (e) => {
                                console.error("读取文件时出错:", e);
                            };
                            reader.readAsText(file);
                        }
                    }
                });
            }
            renderChatList() {
                if (this.chats.length === 0) {
                    this.createNewChat('你是一个简洁的AI智能体助手。');
                }
                this.chatList.innerHTML = '';
                const someVariable = this;
                this.chats.forEach(chat => {
                    const li = document.createElement('li');
                    li.className = 'chat-item' + (chat.id === localStorage.getItem('currentChatId') ? ' active' : '');
                    li.innerHTML = `
                ${chat.prompt.slice(0, 25)}
                <button class="delete-btn" onclick="deleteChat('${chat.id}')">×</button>
            `;
                    li.onclick = () => this.switchChat(chat.id);
                    this.chatList.appendChild(li);
                });
                const chatIndex = this.chats.findIndex(chat => chat.id === localStorage.getItem('currentChatId')) || 0;
                this.loadChat(this.chats[chatIndex]);
            }
            switchChat(chatId) {
                if (localStorage.getItem('currentChatId') === chatId) return;
                const chatIndex = this.chats.findIndex(chat => chat.id === chatId);
                if (chatIndex !== -1) {
                    localStorage.setItem('currentChatId', chatId);
                    this.renderChatList();
                }
            }
            createNewChat(prompt) {
                const chat_id = Date.now().toString();
                this.chats.push({
                    id: chat_id,
                    prompt: prompt,
                    messages: []
                });
                localStorage.setItem('aiChats', JSON.stringify(this.chats));
                localStorage.setItem('currentChatId', chat_id);
            }
            loadChat(chat) {
                this.chatHeader.innerHTML = "";
                const textarea = document.createElement('textarea');
                textarea.textContent = chat.prompt
                const someVariable = this;
                textarea.addEventListener("change", function (event) {
                    const chatIndex = someVariable.chats.findIndex(chat => chat.id === localStorage.getItem('currentChatId'));
                    if (chatIndex !== -1) {
                        someVariable.chats[chatIndex].prompt = event.target.value;
                    }
                })
                this.chatHeader.append(textarea);
                this.chatMessagesDiv.innerHTML = '';
                chat.messages.forEach(msg => {
                    this.showMessage(msg.sender, msg.content);
                });
            }
            deleteChat(chatId) {
                if (confirm('确定要删除这个对话吗？')) {
                    this.chats = this.chats.filter(chat => chat.id !== chatId);
                    if (localStorage.getItem('currentChatId') === chatId && this.chats.length > 0) {
                        localStorage.setItem('currentChatId', this.chats[0].id);
                    }
                    localStorage.setItem('aiChats', JSON.stringify(this.chats));
                    this.renderChatList();
                }
            }
            addMessage(sender, content) {
                const chatIndex = this.chats.findIndex(chat => chat.id === localStorage.getItem('currentChatId'));
                if (chatIndex !== -1) {
                    const msg = { sender: sender, content: content };
                    this.chats[chatIndex].messages.push(msg);
                    localStorage.setItem('aiChats', JSON.stringify(this.chats));
                    //this.showMessage(sender, content);
                }
            }
            showMessage(sender, content) {
                const messageDiv = document.createElement('pre');
                messageDiv.className = `message ${sender === 'user' ? 'user-message' : 'ai-message'}`;
                messageDiv.textContent = content;
                this.chatMessagesDiv.appendChild(messageDiv);
                this.chatMessagesDiv.scrollTop = this.chatMessagesDiv.scrollHeight;
            }
            showMessageImage() {
                const messageDiv = document.createElement('pre');
                messageDiv.className = "message user-message";
                const messageImg = document.createElement('img');
                messageImg.src = this.previewImg.src;
                messageImg.addEventListener("click", function (event) {
                    const modal = document.getElementById('imageModal');
                    const modalImg = document.getElementById('expandedImg');
                    modal.style.display = 'block';
                    modalImg.src = event.target.src;
                })
                messageDiv.appendChild(messageImg);
                this.previewImg.src = "";
                this.previewImg.style.display = 'none';
                this.chatMessagesDiv.appendChild(messageDiv);
                this.chatMessagesDiv.scrollTop = this.chatMessagesDiv.scrollHeight;
            }
        }
        const CM = new ChatManager();
        CM.renderChatList();
        function deleteChat(chatId) {
            CM.deleteChat(chatId);
        }

        /*
        */
    </script>

    <style>
        .zoom-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            padding: 50px;
            background-color: rgba(0, 0, 0, 0.9);
            justify-content: center;
            align-items: center;
            overflow: auto;
        }

        .zoom-modal-content {
            background-color: white;
            padding: 20px;
            border-radius: 10px;
            width: 300px;
            margin: auto;
            display: block;
            width: 90%;
        }

        .zoom-modal-close {
            position: absolute;
            top: 15px;
            right: 35px;
            color: #f1f1f1;
            font-size: 40px;
            font-weight: bold;
            transition: 0.3s;
            cursor: pointer;
        }

        .zoom-modal-close:hover,
        .zoom-modal-close:focus {
            color: #bbb;
            text-decoration: none;
            cursor: pointer;
        }
    </style>
    <!-- 放大预览的模态框 -->
    <div id="imageModal" class="zoom-modal">
        <span class="zoom-modal-close">&times;</span>
        <img id="expandedImg" class="zoom-modal-content">
    </div>
    <script>
        class PreviewImage {
            constructor() {
                this.modal = document.getElementById('imageModal');
                this.modalImg = document.getElementById('expandedImg');
                this.previewImg = document.getElementById('previewImg');
                this.closeBtn = document.getElementsByClassName('zoom-modal-close')[0];
                this.elementListener(this);
            }
            elementListener(someVariable) {
                this.previewImg.onclick = function () { // 点击图片显示模态框
                    someVariable.modal.style.display = 'block';
                    someVariable.modalImg.src = this.src;
                }
                this.closeBtn.onclick = function () { // 点击关闭按钮隐藏模态框
                    someVariable.modal.style.display = 'none';
                }
                this.modal.onclick = function (event) { // 点击模态框背景也隐藏模态框
                    if (event.target === someVariable.modal) {
                        someVariable.modal.style.display = 'none';
                    }
                }
                document.onkeydown = function (event) {// 按ESC键关闭模态框
                    if (event.key === 'Escape' && someVariable.modal.style.display === 'block') {
                        someVariable.modal.style.display = 'none';
                    }
                };
            }
        }
        const PI = new PreviewImage();
    </script>

    <script>
        class EditableContentManager {
            constructor() {
                this.container = document.getElementById('edit-content');
                this.editableItems = [];
                this.init();
            }
            init() {
                this.setupEditableItems();
            }
            setupEditableItems() {
                this.editableItems = Array.from(this.container.querySelectorAll('.editable-item'));
                this.editableItems.forEach(item => {
                    item.addEventListener('dblclick', () => {
                        this.startEditing(item);
                    });
                });
            }
            startEditing(item) {
                if (item.classList.contains('editing')) return;
                const contentElement = item.querySelector('.editable-content');
                const currentValue = contentElement.textContent;
                const input = document.createElement('input');
                input.type = 'text';
                input.className = 'editable-input';
                input.value = currentValue;
                contentElement.style.display = 'none';
                item.appendChild(input);
                item.classList.add('editing');
                input.focus();
                input.select();
                const saveEdit = () => {
                    const newValue = input.value.trim();
                    contentElement.textContent = newValue || currentValue;
                    contentElement.style.display = 'inline';
                    item.removeChild(input);
                    item.classList.remove('editing');
                    input.removeEventListener('blur', saveEdit);
                    input.removeEventListener('keydown', handleKeyDown);

                    this.logAllEditableContents();
                };
                const cancelEdit = () => {
                    contentElement.style.display = 'inline';
                    item.removeChild(input);
                    item.classList.remove('editing');
                    input.removeEventListener('blur', saveEdit);
                    input.removeEventListener('keydown', handleKeyDown);
                };
                const handleKeyDown = (e) => {
                    if (e.key === 'Enter') {
                        saveEdit();
                    } else if (e.key === 'Escape') {
                        cancelEdit();
                    }
                };
                input.addEventListener('blur', saveEdit);
                input.addEventListener('keydown', handleKeyDown);
            }
            logAllEditableContents() {
                const editableContents = this.container.querySelectorAll('.editable-content');
                const items = Array.from(editableContents).map(item => item.textContent);
                console.log(items);
            }
            refreshEditableItems() {
                this.setupEditableItems();
            }
        }
        const editableManager = new EditableContentManager();
    </script>
</body>

</html>